package com.example.androidaudiovideodemo.activity

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.media.*
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.content.FileProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.blankj.utilcode.util.*
import com.example.androidaudiovideodemo.R
import com.example.androidaudiovideodemo.VideoAudioListAdapter
import com.example.androidaudiovideodemo.base.BaseActivity
import com.example.androidaudiovideodemo.utils.VideoSplitBean
import kotlinx.android.synthetic.main.activity_video_analysis_and_enclosure.*
import java.io.File
import java.io.FileOutputStream
import java.lang.Exception
import java.nio.ByteBuffer
import java.util.*
import kotlin.concurrent.thread

/**
 *
 * author: renbing
 *
 * date: 2021/12/29
 *
 * des:4. 学习 Android 平台的 MediaExtractor 和 MediaMuxer API，知道如何解析和封装 mp4 文件
 */
class AnalysisAndEnclosureVideoActivity : BaseActivity(){

    private var mMediaExtractor: MediaExtractor? = null
    private var mAudioMediaMuxer: MediaMuxer? = null
    private var mVideoMediaMuxer: MediaMuxer? = null
    private val mListDatas = arrayListOf<VideoSplitBean>()
    private var mAdapter: VideoAudioListAdapter? = null
    private var mIsPlaying = false

    override fun getLayoutId() = R.layout.activity_video_analysis_and_enclosure

    override fun performInit() {
        super.performInit()

        setStatusBarColor(this,true)
    }

    override fun initData() {
        super.initData()
        //返回按钮
        task_four_title_view.run {
            setLeftIconColorFilter(Color.BLACK)
            setOnLeftIconClickListener {
                finish()
            }
        }

        mMediaExtractor = MediaExtractor()
        mAdapter = VideoAudioListAdapter(this@AnalysisAndEnclosureVideoActivity,mListDatas,{ position, data -> itemClick(position, data) },{position, data -> return@VideoAudioListAdapter itemLongClick(position, data)})

        initRecyclerView()

        if (ActivityCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
            PermissionUtils.permission(Manifest.permission.READ_EXTERNAL_STORAGE)
                .callback(object : PermissionUtils.SimpleCallback{
                    override fun onGranted() {
                        readDocument()
                    }

                    override fun onDenied() {
                        ToastUtils.showShort("拒绝访问文件")
                    }

                }).request()
        }else{
            readDocument()
        }
    }

    /**
     * 列表单击事件  点击播放
     */
    private fun itemClick(position: Int,data: VideoSplitBean){
        if (mIsPlaying) return
        if (data.name?.startsWith("split-") == true){
            val rootDir = FileUtils.getFileByPath("${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/video_split")
            if (!rootDir.exists()){
                ToastUtils.showShort("文件路径已损坏")
                return
            }
            val audioDir = File(rootDir,"audio")
            val videoDir = File(rootDir,"video")
            if (!audioDir.exists() && audioDir.isDirectory){
                ToastUtils.showShort("文件路径已损坏")
                return
            }
            if (!videoDir.exists() && videoDir.isDirectory){
                ToastUtils.showShort("文件路径已损坏")
                return
            }
            data.name.run {
                when{
                    this.endsWith(".mp3") ->{
                        audioDir.listFiles()?.forEach {
                            if (it.name == data.name){
                                audioPlay(it)
                            }
                        }
                    }
                    this.endsWith(".mp4") ->{
                        videoDir.listFiles()?.forEach {
                            if (it.name == data.name){
                                videoPlay(it)
                            }
                        }
                    }
                    else ->{}
                }
            }
        }else if (data.name?.startsWith("combine-") == true){
            val rootDir = FileUtils.getFileByPath("${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/video_combine")
            if (!rootDir.exists()){
                ToastUtils.showShort("文件路径已损坏")
                return
            }
            rootDir.listFiles()?.forEach {
                if (it.name == data.name){
                    videoPlay(it)
                }
            }
        }

    }

    /**
     * 列表长按事件  选中合成
     */
    private fun itemLongClick(position: Int,data: VideoSplitBean): Boolean{
        val nameLen = data.name?.length?:0
        if (nameLen < 4) {
            ToastUtils.showShort("目标文件已损坏")
            return true
        }
        var lastIndex = 0
        mListDatas.forEachIndexed { index, videoSplitBean ->
            if (videoSplitBean.name?.endsWith(data.name?.substring(nameLen-4)?:"") == true){
                if (videoSplitBean.isSelected) lastIndex = index
                videoSplitBean.isSelected = videoSplitBean.name == data.name
            }
        }
        mAdapter?.notifyItemRangeChanged(position,1)
        mAdapter?.notifyItemRangeChanged(lastIndex,1)
        return true
    }

    /**
     * 播放音频（mp3）
     */
    private fun audioPlay(file: File){
        val mediaPlayer = MediaPlayer()
        mediaPlayer.setDataSource(file.absolutePath)
        mediaPlayer.prepareAsync()
        val timer = Timer()
        mediaPlayer.setOnPreparedListener {
            mIsPlaying = true
            val length = mediaPlayer.duration.toString().length
            val totalDuration = mediaPlayer.duration.toString().substring(0,length-3)
            runOnUiThread { audio_duration.text = "0/$totalDuration" }
            val timerTask = object : TimerTask(){
                override fun run() {
                    if (!mIsPlaying){
                        timer.cancel()
                        return
                    }
                    Log.e("TAG",mediaPlayer.currentPosition.toString())
                    val curLength = mediaPlayer.currentPosition.toString().length
                    val curDuration = mediaPlayer.currentPosition.toString().substring(0,(curLength-3).coerceAtLeast(0))
                    runOnUiThread { audio_duration.text = "$curDuration/$totalDuration" }
                }

            }
            timer.schedule(timerTask,0,1000)
            mediaPlayer.start()
        }
        mediaPlayer.setOnCompletionListener {
            Log.e("TAG","播放完毕")
            ToastUtils.showShort("播放完毕")
            mediaPlayer.release()
            mIsPlaying = false
        }

    }

    /**
     * 播放视频（mp4）
     */
    private fun videoPlay(file: File){
        val intent = Intent(Intent.ACTION_VIEW)
        val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
            FileProvider.getUriForFile(this,"com.example.androidaudiovideodemo.fileprovider",file)
        }else{
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            Uri.fromFile(file)
        }
        intent.setDataAndType(uri,"video/*")
        startActivity(intent)
    }

    private fun initRecyclerView(){
        audio_video_list_rv.apply {
            layoutManager = LinearLayoutManager(this@AnalysisAndEnclosureVideoActivity)
            adapter = mAdapter
        }
    }

    /**
     * 读取内存文件
     */
    private fun readDocument(){
        val rootProPath = "${SDCardUtils.getSDCardPathByEnvironment()}/$packageName"
        val rootProFile = File(rootProPath)
        if (!rootProFile.exists()) return
        val rootSplitDir = File(rootProFile,"video_split")
        if (rootSplitDir.exists()){
            val videoDir = File(rootSplitDir,"video")
            val audioDir = File(rootSplitDir,"audio")
            if (videoDir.exists() && videoDir.isDirectory){
                videoDir.listFiles()?.forEach {
                    val fileModifiedTime = TimeUtils.millis2String(it.lastModified(), "yyyy-MM-dd HH:mm")
                    val listData = VideoSplitBean(it.name, FileUtils.getSize(it),fileModifiedTime)
                    mListDatas.add(listData)
                }
            }
            if (audioDir.exists() && audioDir.isDirectory){
                audioDir.listFiles()?.forEach {
                    val fileModifiedTime = TimeUtils.millis2String(it.lastModified(), "yyyy-MM-dd HH:mm")
                    val listData = VideoSplitBean(it.name, FileUtils.getSize(it),fileModifiedTime)
                    mListDatas.add(listData)
                }
            }
        }
        val rootCombineDir = File(rootProFile,"video_combine")
        if (rootCombineDir.exists() && rootCombineDir.isDirectory){
            rootCombineDir.listFiles()?.forEach {
                val fileModifiedTime = TimeUtils.millis2String(it.lastModified(), "yyyy-MM-dd HH:mm")
                val listData = VideoSplitBean(it.name, FileUtils.getSize(it),fileModifiedTime)
                mListDatas.add(listData)
            }
        }
        if (mListDatas.isNotEmpty()){
            mAdapter?.notifyDataSetChanged()
        }
    }

    override fun initListener() {
        super.initListener()

        //解析视频
        analysis_video.setOnClickListener {
            openDocument()
        }
        //封装视频
        enclosure_video.setOnClickListener {
            enclosureVideo()
        }
    }

    /**
     * 解析
     */
    private fun analysisVideo(sourceFile: File){
        thread {
            var videoOutputStream: FileOutputStream? = null
            var audioOutputStream: FileOutputStream? = null
            try {
                val rootPro = "${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/video_split"
                val videoDir = File(rootPro, "video")
                val audioDir = File(rootPro, "audio")
                if (!videoDir.exists()) {
                    videoDir.mkdirs()
                }
                if (!audioDir.exists()) {
                    audioDir.mkdirs()
                }
                val videoFile = File(videoDir, "split-${System.currentTimeMillis()}-video.mp4")
                val audioFile = File(audioDir, "split-${System.currentTimeMillis()}-audio.mp3")
                videoOutputStream = FileOutputStream(videoFile)
                audioOutputStream = FileOutputStream(audioFile)

                mVideoMediaMuxer = MediaMuxer(videoFile.absolutePath,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
                mAudioMediaMuxer = MediaMuxer(audioFile.absolutePath,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
                var videoFormat: MediaFormat? = null
                var audioFormat: MediaFormat? = null

                //设置源文件
                mMediaExtractor?.setDataSource(sourceFile.absolutePath?:"")
                val trackCount = mMediaExtractor?.trackCount?:0

                var videoTrackIndex = 0
                var audioTrackIndex = 0
                for (i in 0 until trackCount) {
                    val mineType = mMediaExtractor?.getTrackFormat(i)?.getString(MediaFormat.KEY_MIME) ?: ""
                    if (mineType.startsWith("video/")) {
                        videoTrackIndex = i
                        videoFormat = mMediaExtractor?.getTrackFormat(i)
                    }
                    if (mineType.startsWith("audio/")) {
                        audioTrackIndex = i
                        audioFormat = mMediaExtractor?.getTrackFormat(i)
                    }
                }

                val newVideoTrackIndex = mVideoMediaMuxer?.addTrack(videoFormat!!)
                val newAudioTrackIndex = mAudioMediaMuxer?.addTrack(audioFormat!!)

                val byteBuffer = ByteBuffer.allocate(500 * 1024)
                val videoBufferInfo = MediaCodec.BufferInfo()
                val audioBufferInfo = MediaCodec.BufferInfo()
                mVideoMediaMuxer?.start()
                mAudioMediaMuxer?.start()
                //切换到视频信道
                mMediaExtractor?.selectTrack(videoTrackIndex)
                while (true) {
                    val readSampleCount = mMediaExtractor?.readSampleData(byteBuffer, 0)?:-1
                    if (readSampleCount < 0) {
                        mMediaExtractor?.unselectTrack(videoTrackIndex)

                        Log.e("TAG", "视频分离完成")
                        break
                    }
                    videoBufferInfo.run {
                        size = readSampleCount
                        flags = mMediaExtractor?.sampleFlags?:0
                        offset = 0
                        presentationTimeUs = mMediaExtractor?.sampleTime?:0L
                    }
                    mVideoMediaMuxer?.writeSampleData(newVideoTrackIndex?:1,byteBuffer,videoBufferInfo)

//                    val buffer = ByteArray(readSampleCount)
//                    byteBuffer.get(buffer)
//                    videoOutputStream.write(buffer)
                    byteBuffer.clear()
                    mMediaExtractor?.advance()
                }
                //切换到视频信道
                mMediaExtractor?.selectTrack(audioTrackIndex)
                while (true) {
                    val readSampleCount = mMediaExtractor?.readSampleData(byteBuffer, 0)?:-1
                    if (readSampleCount < 0) {
                        mMediaExtractor?.unselectTrack(audioTrackIndex)
                        Log.e("TAG", "音频分离完成")
                        break
                    }
                    audioBufferInfo.run {
                        size = readSampleCount
                        flags = mMediaExtractor?.sampleFlags?:0
                        offset = 0
                        presentationTimeUs = mMediaExtractor?.sampleTime?:0L
                    }
                    mAudioMediaMuxer?.writeSampleData(newAudioTrackIndex?:0,byteBuffer,audioBufferInfo)
//                    val buffer = ByteArray(readSampleCount)
//                    byteBuffer.get(buffer)
//                    audioOutputStream.write(buffer)
                    byteBuffer.clear()
                    mMediaExtractor?.advance()
                }
                updateList(videoFile)
                updateList(audioFile)
                runOnUiThread {
                    mAdapter?.notifyItemRangeInserted(0,2)
                    audio_video_list_rv.smoothScrollToPosition(0)
                    ToastUtils.showShort("分离完成")
                }
                mVideoMediaMuxer?.stop()
                mVideoMediaMuxer?.release()
                mAudioMediaMuxer?.stop()
                mAudioMediaMuxer?.release()
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                mMediaExtractor?.release()
                videoOutputStream?.close()
                audioOutputStream?.close()
            }
        }
    }

    /**
     * 更新列表
     */
    private fun updateList(file: File){
        val modifiedTime = TimeUtils.millis2String(file.lastModified(),"yyyy-MM-dd HH:mm")
        val data = VideoSplitBean(file.name, FileUtils.getSize(file),modifiedTime)
        mListDatas.add(0,data)
    }

    /**
     * 封装
     */
    @SuppressLint("WrongConstant")
    private fun enclosureVideo(){
        val audioAndVideoList = arrayListOf<VideoSplitBean>()
        mListDatas.forEach {
            if (it.isSelected){
                audioAndVideoList.add(it)
            }
            if (audioAndVideoList.size > 2)return@forEach
        }
        if (audioAndVideoList.size != 2){
            ToastUtils.showShort("请确保选择的音频和视频各为1个")
            return
        }
        var audioCount = 0
        var audioName = ""
        var videoName = ""
        audioAndVideoList.forEach {
            if (it.name?.endsWith(".mp3") == true){
                audioCount+=1
                audioName = it.name
            }
            if (it.name?.endsWith(".mp4") == true){
                videoName = it.name
            }
        }
        if (audioCount != 1){
            ToastUtils.showShort("请确保选择的音频和视频各为1个")
            return
        }
        val audioExtractor = MediaExtractor()
        var audioTrackIndex = -1
        var newAudioTrackIndex = -1
        var audioMaxInputSize = 0
        val videoExtractor = MediaExtractor()
        var videoTrackIndex = -1
        var newVideoTrackIndex = -1
        var videoMaxInputSize = 0
        var frameRate = 0
        var frameDuration = 0L
        var muxer: MediaMuxer? = null
        try {
            val outPutPath = "${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/video_combine"
            val outDir = File(outPutPath)
            if (!outDir.exists()){
                outDir.mkdirs()
            }
            val outFile = File(outDir,"combine-${System.currentTimeMillis()}.mp4")
            if (!outFile.exists()){
                outFile.createNewFile()
            }
            muxer = MediaMuxer(outFile.absolutePath,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
            getFileByName(audioName)?.run {
                audioExtractor.setDataSource(this.absolutePath)
                //获取轨道数
                val audioTrackCount = audioExtractor.trackCount
                //遍历轨道获取音频轨
                for (i in 0 until audioTrackCount){
                    val audioFormat = audioExtractor.getTrackFormat(i)
                    val mimeType = audioFormat.getString(MediaFormat.KEY_MIME)?:""
                    if (mimeType.startsWith("audio/")){
                        //获取音轨索引
                        audioTrackIndex = i
                        //合成时新的音频轨道索引
                        newAudioTrackIndex = muxer.addTrack(audioFormat)
                        //音频最大输入
                        audioMaxInputSize = audioFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
                    }
                }
            }
            getFileByName(videoName)?.run {
                videoExtractor.setDataSource(this.absolutePath)
                val videoTrackCount = videoExtractor.trackCount
                for (i in 0 until videoTrackCount){
                    val videoFormat = videoExtractor.getTrackFormat(i)
                    val mimeType = videoFormat.getString(MediaFormat.KEY_MIME)?:""
                    if (mimeType.startsWith("video/")){
                        videoTrackIndex = i
                        newVideoTrackIndex = muxer.addTrack(videoFormat)
                        videoMaxInputSize = videoFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
                        frameRate = videoFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
                        frameDuration = videoFormat.getLong(MediaFormat.KEY_DURATION)
                    }
                }
            }
            muxer.start()
            //合成音频
            muxer(audioExtractor,muxer,audioTrackIndex,newAudioTrackIndex,audioMaxInputSize,frameDuration)
            //合成视频
            muxer(videoExtractor,muxer,videoTrackIndex,newVideoTrackIndex,videoMaxInputSize,frameDuration)

            //更新列表数据
            updateList(outFile)
            //更新界面
            runOnUiThread {
                mAdapter?.notifyItemRangeInserted(0,1)
                audio_video_list_rv.smoothScrollToPosition(0)
                ToastUtils.showShort("封装完成")
            }
        }catch (e: Exception){
            e.printStackTrace()
        }finally {
            audioExtractor.release()
            videoExtractor.release()
            muxer?.stop()
            muxer?.release()
        }
    }

    /**
     * 合成
     */
    private fun muxer(extractor: MediaExtractor?,muxer: MediaMuxer?,audioTrackIndex: Int,newAudioTrackIndex: Int,audioMaxInputSize: Int,frameDuration: Long){
        extractor?.selectTrack(audioTrackIndex)
        val audioBufferInfo = MediaCodec.BufferInfo()
        val audioByteBuffer = ByteBuffer.allocate(audioMaxInputSize)
        while (true){
            val readSampleSize = extractor?.readSampleData(audioByteBuffer,0)?:0
            if (readSampleSize < 0){
                extractor?.unselectTrack(audioTrackIndex)
                break
            }
            //获取当前展示样本的时间
            val sampleTime = extractor?.sampleTime?:0
            if (sampleTime < 0){
                extractor?.advance()
                continue
            }
            if (sampleTime > 0+frameDuration){
                break
            }
            audioBufferInfo.run {
                size = readSampleSize
                offset = 0
                flags = extractor?.sampleFlags?:0
                presentationTimeUs = sampleTime - 0
            }
            muxer?.writeSampleData(newAudioTrackIndex,audioByteBuffer,audioBufferInfo)
            extractor?.advance()
        }
    }

    private fun getFileByName(name: String): File?{
        val rootDir = FileUtils.getFileByPath("${SDCardUtils.getSDCardPathByEnvironment()}/$packageName/video_split")
        if (!rootDir.exists()){
            ToastUtils.showShort("文件已损坏")
            return null
        }
        val audioDir = File(rootDir,"audio")
        val videoDir = File(rootDir,"video")
        if (!audioDir.exists() && audioDir.isDirectory){
            ToastUtils.showShort("文件已损坏")
            return null
        }
        if (!videoDir.exists() && videoDir.isDirectory){
            ToastUtils.showShort("文件已损坏")
            return null
        }
        when{
            name.endsWith(".mp3") ->{
                audioDir.listFiles()?.forEach {
                    if (it.name == name){
                        return it
                    }
                }
            }
            name.endsWith(".mp4") ->{
                videoDir.listFiles()?.forEach {
                    if (it.name == name){
                        return it
                    }
                }
            }
        }
        ToastUtils.showShort("文件已损坏")
        return null
    }

    private fun openDocument(){
        if (ActivityCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
            PermissionUtils.permission(Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .callback(object : PermissionUtils.SimpleCallback{
                    override fun onGranted() {
                        openDocument()
                    }

                    override fun onDenied() {
                        ToastUtils.showShort("拒绝访问，已取消操作")
                        return
                    }

                }).request()
        }else{
            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT,null).apply { setDataAndType(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,"video/*") }
            startActivityForResult(intent,1)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 1 && resultCode == RESULT_OK){
            Log.e("TAG","文件路径：${UriUtils.uri2File(data?.data).absolutePath}")
            analysisVideo(UriUtils.uri2File(data?.data))
        }
    }
}